package org.cybzacg.encryption.utils;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

/**
 * 性能监控工具类
 * 提供加密操作的性能统计和监控功能
 * 
 * @author encryption team
 * @version 1.0
 */
public class PerformanceUtils {
    
    // 性能统计映射
    private static final Map<String, PerformanceMetrics> metricsMap = new ConcurrentHashMap<>();
    
    // 全局统计
    private static final AtomicLong totalOperations = new AtomicLong(0);
    private static final AtomicLong totalExecutionTime = new AtomicLong(0);
    private static final AtomicLong totalMemoryUsed = new AtomicLong(0);
    private static final AtomicInteger activeThreads = new AtomicInteger(0);
    
    /**
     * 性能指标类
     */
    public static class PerformanceMetrics {
        private final String operationName;
        private final AtomicLong operationCount = new AtomicLong(0);
        private final AtomicLong totalExecutionTime = new AtomicLong(0);
        private final AtomicLong minExecutionTime = new AtomicLong(Long.MAX_VALUE);
        private final AtomicLong maxExecutionTime = new AtomicLong(0);
        private final AtomicLong totalMemoryUsed = new AtomicLong(0);
        private final AtomicLong minMemoryUsed = new AtomicLong(Long.MAX_VALUE);
        private final AtomicLong maxMemoryUsed = new AtomicLong(0);
        private final AtomicInteger errorCount = new AtomicInteger(0);
        private final long startTime;
        
        public PerformanceMetrics(String operationName) {
            this.operationName = operationName;
            this.startTime = System.currentTimeMillis();
        }
        
        /**
         * 记录操作性能
         * 
         * @param executionTime 执行时间（纳秒）
         * @param memoryUsed 内存使用量（字节）
         * @param success 是否成功
         */
        public void recordOperation(long executionTime, long memoryUsed, boolean success) {
            operationCount.incrementAndGet();
            totalExecutionTime.addAndGet(executionTime);
            totalMemoryUsed.addAndGet(memoryUsed);
            
            if (!success) {
                errorCount.incrementAndGet();
            }
            
            // 更新最小/最大执行时间
            updateMin(minExecutionTime, executionTime);
            updateMax(maxExecutionTime, executionTime);
            
            // 更新最小/最大内存使用
            updateMin(minMemoryUsed, memoryUsed);
            updateMax(maxMemoryUsed, memoryUsed);
        }
        
        /**
         * 更新最小值
         */
        private void updateMin(AtomicLong minField, long value) {
            long current = minField.get();
            while (value < current && !minField.compareAndSet(current, value)) {
                current = minField.get();
            }
        }
        
        /**
         * 更新最大值
         */
        private void updateMax(AtomicLong maxField, long value) {
            long current = maxField.get();
            while (value > current && !maxField.compareAndSet(current, value)) {
                current = maxField.get();
            }
        }
        
        /**
         * 获取操作名称
         */
        public String getOperationName() {
            return operationName;
        }
        
        /**
         * 获取操作次数
         */
        public long getOperationCount() {
            return operationCount.get();
        }
        
        /**
         * 获取平均执行时间（纳秒）
         */
        public double getAverageExecutionTime() {
            long count = operationCount.get();
            return count > 0 ? (double) totalExecutionTime.get() / count : 0.0;
        }
        
        /**
         * 获取最小执行时间（纳秒）
         */
        public long getMinExecutionTime() {
            long min = minExecutionTime.get();
            return min == Long.MAX_VALUE ? 0 : min;
        }
        
        /**
         * 获取最大执行时间（纳秒）
         */
        public long getMaxExecutionTime() {
            return maxExecutionTime.get();
        }
        
        /**
         * 获取总执行时间（纳秒）
         */
        public long getTotalExecutionTime() {
            return totalExecutionTime.get();
        }
        
        /**
         * 获取平均内存使用量（字节）
         */
        public double getAverageMemoryUsed() {
            long count = operationCount.get();
            return count > 0 ? (double) totalMemoryUsed.get() / count : 0.0;
        }
        
        /**
         * 获取最小内存使用量（字节）
         */
        public long getMinMemoryUsed() {
            long min = minMemoryUsed.get();
            return min == Long.MAX_VALUE ? 0 : min;
        }
        
        /**
         * 获取最大内存使用量（字节）
         */
        public long getMaxMemoryUsed() {
            return maxMemoryUsed.get();
        }
        
        /**
         * 获取总内存使用量（字节）
         */
        public long getTotalMemoryUsed() {
            return totalMemoryUsed.get();
        }
        
        /**
         * 获取错误次数
         */
        public int getErrorCount() {
            return errorCount.get();
        }
        
        /**
         * 获取成功率
         */
        public double getSuccessRate() {
            long total = operationCount.get();
            long errors = errorCount.get();
            return total > 0 ? (double) (total - errors) / total * 100.0 : 0.0;
        }
        
        /**
         * 获取运行时间（毫秒）
         */
        public long getUptime() {
            return System.currentTimeMillis() - startTime;
        }
        
        /**
         * 获取吞吐量（操作/秒）
         */
        public double getThroughput() {
            long uptimeMs = getUptime();
            return uptimeMs > 0 ? (double) operationCount.get() / (uptimeMs / 1000.0) : 0.0;
        }
        
        /**
         * 重置统计信息
         */
        public void reset() {
            operationCount.set(0);
            totalExecutionTime.set(0);
            minExecutionTime.set(Long.MAX_VALUE);
            maxExecutionTime.set(0);
            totalMemoryUsed.set(0);
            minMemoryUsed.set(Long.MAX_VALUE);
            maxMemoryUsed.set(0);
            errorCount.set(0);
        }
        
        @Override
        public String toString() {
            return String.format(
                "PerformanceMetrics[%s]:\n" +
                "  Operations: %d\n" +
                "  Success Rate: %.2f%%\n" +
                "  Avg Execution Time: %.2f μs\n" +
                "  Min/Max Execution Time: %d/%d μs\n" +
                "  Avg Memory Used: %.2f KB\n" +
                "  Min/Max Memory Used: %d/%d KB\n" +
                "  Throughput: %.2f ops/sec\n" +
                "  Uptime: %d ms",
                operationName,
                getOperationCount(),
                getSuccessRate(),
                getAverageExecutionTime() / 1000.0,
                getMinExecutionTime() / 1000,
                getMaxExecutionTime() / 1000,
                getAverageMemoryUsed() / 1024.0,
                getMinMemoryUsed() / 1024,
                getMaxMemoryUsed() / 1024,
                getThroughput(),
                getUptime()
            );
        }
    }
    
    /**
     * 开始性能监控
     * 
     * @param operationName 操作名称
     * @return 性能监控上下文
     */
    public static PerformanceContext startMonitoring(String operationName) {
        totalOperations.incrementAndGet();
        activeThreads.incrementAndGet();
        
        PerformanceMetrics metrics = metricsMap.computeIfAbsent(
            operationName, 
            PerformanceMetrics::new
        );
        
        return new PerformanceContext(operationName, metrics);
    }
    
    /**
     * 性能监控上下文
     */
    public static class PerformanceContext implements AutoCloseable {
        private final String operationName;
        private final PerformanceMetrics metrics;
        private final long startTime;
        private final long startMemory;
        
        private PerformanceContext(String operationName, PerformanceMetrics metrics) {
            this.operationName = operationName;
            this.metrics = metrics;
            this.startTime = System.nanoTime();
            this.startMemory = getCurrentMemoryUsage();
        }
        
        /**
         * 结束监控并记录结果
         * 
         * @param success 是否成功
         * @return 性能统计信息
         */
        public PerformanceResult end(boolean success) {
            long endTime = System.nanoTime();
            long endMemory = getCurrentMemoryUsage();
            
            long executionTime = endTime - startTime;
            long memoryUsed = Math.max(0, endMemory - startMemory);
            
            metrics.recordOperation(executionTime, memoryUsed, success);
            
            // 更新全局统计
            totalExecutionTime.addAndGet(executionTime);
            totalMemoryUsed.addAndGet(memoryUsed);
            activeThreads.decrementAndGet();
            
            return new PerformanceResult(
                operationName,
                executionTime,
                memoryUsed,
                success,
                metrics
            );
        }
        
        /**
         * 结束监控（成功）
         */
        public PerformanceResult end() {
            return end(true);
        }
        
        @Override
        public void close() {
            end();
        }
        
        /**
         * 获取已用时间（纳秒）
         */
        public long getElapsedTime() {
            return System.nanoTime() - startTime;
        }
        
        /**
         * 获取已用内存（字节）
         */
        public long getUsedMemory() {
            return Math.max(0, getCurrentMemoryUsage() - startMemory);
        }
    }
    
    /**
     * 性能结果类
     */
    public static class PerformanceResult {
        private final String operationName;
        private final long executionTime;
        private final long memoryUsed;
        private final boolean success;
        private final PerformanceMetrics metrics;
        
        public PerformanceResult(String operationName, long executionTime, 
                                long memoryUsed, boolean success, PerformanceMetrics metrics) {
            this.operationName = operationName;
            this.executionTime = executionTime;
            this.memoryUsed = memoryUsed;
            this.success = success;
            this.metrics = metrics;
        }
        
        public String getOperationName() {
            return operationName;
        }
        
        public long getExecutionTime() {
            return executionTime;
        }
        
        public long getMemoryUsed() {
            return memoryUsed;
        }
        
        public boolean isSuccess() {
            return success;
        }
        
        public PerformanceMetrics getMetrics() {
            return metrics;
        }
        
        public double getExecutionTimeMs() {
            return executionTime / 1_000_000.0;
        }
        
        public double getMemoryUsedKB() {
            return memoryUsed / 1024.0;
        }
        
        @Override
        public String toString() {
            return String.format(
                "PerformanceResult[%s]: time=%.2fms, memory=%.2fKB, success=%s",
                operationName, getExecutionTimeMs(), getMemoryUsedKB(), success
            );
        }
    }
    
    /**
     * 获取操作的性能指标
     * 
     * @param operationName 操作名称
     * @return 性能指标
     */
    public static PerformanceMetrics getMetrics(String operationName) {
        return metricsMap.get(operationName);
    }
    
    /**
     * 获取所有性能指标
     * 
     * @return 性能指标映射的副本
     */
    public static Map<String, PerformanceMetrics> getAllMetrics() {
        return new ConcurrentHashMap<>(metricsMap);
    }
    
    /**
     * 获取全局统计信息
     * 
     * @return 全局统计信息
     */
    public static GlobalStatistics getGlobalStatistics() {
        return new GlobalStatistics(
            totalOperations.get(),
            totalExecutionTime.get(),
            totalMemoryUsed.get(),
            activeThreads.get(),
            metricsMap.size()
        );
    }
    
    /**
     * 全局统计信息类
     */
    public static class GlobalStatistics {
        private final long totalOperations;
        private final long totalExecutionTime;
        private final long totalMemoryUsed;
        private final int activeThreads;
        private final int trackedOperations;
        
        public GlobalStatistics(long totalOperations, long totalExecutionTime, 
                               long totalMemoryUsed, int activeThreads, int trackedOperations) {
            this.totalOperations = totalOperations;
            this.totalExecutionTime = totalExecutionTime;
            this.totalMemoryUsed = totalMemoryUsed;
            this.activeThreads = activeThreads;
            this.trackedOperations = trackedOperations;
        }
        
        public long getTotalOperations() {
            return totalOperations;
        }
        
        public long getTotalExecutionTime() {
            return totalExecutionTime;
        }
        
        public double getAverageExecutionTime() {
            return totalOperations > 0 ? (double) totalExecutionTime / totalOperations : 0.0;
        }
        
        public long getTotalMemoryUsed() {
            return totalMemoryUsed;
        }
        
        public double getAverageMemoryUsed() {
            return totalOperations > 0 ? (double) totalMemoryUsed / totalOperations : 0.0;
        }
        
        public int getActiveThreads() {
            return activeThreads;
        }
        
        public int getTrackedOperations() {
            return trackedOperations;
        }
        
        @Override
        public String toString() {
            return String.format(
                "GlobalStatistics:\n" +
                "  Total Operations: %d\n" +
                "  Active Threads: %d\n" +
                "  Tracked Operations: %d\n" +
                "  Avg Execution Time: %.2f μs\n" +
                "  Avg Memory Used: %.2f KB\n" +
                "  Total Execution Time: %.2f ms\n" +
                "  Total Memory Used: %.2f MB",
                totalOperations,
                activeThreads,
                trackedOperations,
                getAverageExecutionTime() / 1000.0,
                getAverageMemoryUsed() / 1024.0,
                getTotalExecutionTime() / 1_000_000.0,
                getTotalMemoryUsed() / (1024.0 * 1024.0)
            );
        }
    }
    
    /**
     * 重置指定操作的性能统计
     * 
     * @param operationName 操作名称
     */
    public static void resetMetrics(String operationName) {
        PerformanceMetrics metrics = metricsMap.get(operationName);
        if (metrics != null) {
            metrics.reset();
        }
    }
    
    /**
     * 重置所有性能统计
     */
    public static void resetAllMetrics() {
        metricsMap.values().forEach(PerformanceMetrics::reset);
        totalOperations.set(0);
        totalExecutionTime.set(0);
        totalMemoryUsed.set(0);
        activeThreads.set(0);
    }
    
    /**
     * 获取性能报告
     * 
     * @return 性能报告
     */
    public static String getPerformanceReport() {
        StringBuilder sb = new StringBuilder();
        sb.append("=== Performance Report ===\n\n");
        
        // 全局统计
        sb.append(getGlobalStatistics()).append("\n\n");
        
        // 各操作统计
        List<String> operationNames = new ArrayList<>(metricsMap.keySet());
        Collections.sort(operationNames);
        
        for (String operationName : operationNames) {
            PerformanceMetrics metrics = metricsMap.get(operationName);
            sb.append(metrics).append("\n\n");
        }
        
        return sb.toString();
    }
    
    /**
     * 获取当前内存使用量（字节）
     */
    private static long getCurrentMemoryUsage() {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }
    
    /**
     * 获取系统信息
     * 
     * @return 系统信息
     */
    public static String getSystemInfo() {
        Runtime runtime = Runtime.getRuntime();
        return String.format(
            "System Information:\n" +
            "  Available Processors: %d\n" +
            "  Max Memory: %.2f MB\n" +
            "  Total Memory: %.2f MB\n" +
            "  Free Memory: %.2f MB\n" +
            "  Used Memory: %.2f MB",
            runtime.availableProcessors(),
            runtime.maxMemory() / (1024.0 * 1024.0),
            runtime.totalMemory() / (1024.0 * 1024.0),
            runtime.freeMemory() / (1024.0 * 1024.0),
            getCurrentMemoryUsage() / (1024.0 * 1024.0)
        );
    }
    
    /**
     * 创建性能监控的装饰器
     * 
     * @param operationName 操作名称
     * @param operation 要监控的操作
     * @return 装饰后的操作
     */
    public static <T> T monitor(String operationName, ThrowingSupplier<T> operation) throws Exception {
        try (PerformanceContext context = startMonitoring(operationName)) {
            T result = operation.get();
            context.end(true);
            return result;
        } catch (Exception e) {
            try (PerformanceContext context = startMonitoring(operationName)) {
                context.end(false);
            }
            throw e;
        }
    }
    
    /**
     * 函数式接口
     */
    @FunctionalInterface
    public interface ThrowingSupplier<T> {
        T get() throws Exception;
    }
}
